In most cases, the parameters coming from the trackers have a fixed format and describe a certain state of the object. Therefore, they can be unambiguously interpreted by Wialon and displayed in messages. However, some trackers can record information of different content or even several different blocks of information in one parameter. In this case, for its correct display in Wialon, you will need to configure the sensor in a special way. To do this, you need to use bitwise parameter control, which we will discuss in this article.
Challenge
Some trackers allow transmitting user parameters with content that may vary depending on the device configuration.
For example, Wialon may display the user_value = 2646793773 parameter, although the tracker was supposed to pass one of the following values:
- 2646793773, an unsigned integer;
- 56877 and 40386 — several integers;
- −499310125, an integer with a sign bit;
- −5.15811×10−21 or −0.00000000000000000000515811, a floating-point number;
- etc.
Theoretically, this problem can be solved on the Wialon side by changing the script that parses the data coming from the tracker. However, this will affect all the users, and they may have different tracker configurations, meaning they may expect different results of data parsing from the script. Fortunately, a method for solving this problem that will work for everyone exists: creating a sensor with the right formula. At the same time, it will be based on the representation of the parameter in the binary numeral system since we already know that the representation in the decimal numeral system can be different. In binary form, the value of the parameter from the example above is written as follows: 1001 1101 1100 0010 1101 1110 0010 1101. Now let's figure out how to work with the binary numeral system.
Theoretical background
This section will cover the information needed to apply further formulas.
Numeral systems
In mathematics, different numeral systems are used. The most conventional for most people sense are positional numeral systems, where the value of a digit is determined by its position. For example, within the decimal system, the number 1, depending on the position in the number, can mean one unit (1), one ten (10), one hundred (100), and so on.
The number of characters used in positional numeral systems is called the base.
The table below lists a few common numeral systems:
Name | Symbol | Base | Application field | Characters used |
---|---|---|---|---|
Binary | BIN | 2 | Discrete mathematics, computer science, programming | 0, 1 |
Decimal | DEC | 10 | Everywhere | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 |
Hexadecimal | HEX | 16 | Computer science, programming | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F |
To quickly convert numbers from one numeral system to another, you can use the Calculator application (it is preinstalled on every computer, or its analogs can be found on the internet) in the Programming mode (or similar).
You can come up with and use any numeral system, for example, base thirteen, but it is not generally accepted, which can lead to difficulties in parsing data on the receiving side.
The use of different numeral systems has not only historical or cultural reasons but also practical grounds. The binary system is unusual for humans but significantly simplifies mathematical calculations for electronic devices. Also, the binary system is convenient in terms of ease of recognizing values in the presence of noise, since it is easier to distinguish the absence of voltage from its presence than to determine a specific voltage level from 0 to 9.
Bits and bytes
A bit is one digit of a binary code.
A byte is a group of 8 bits.
A nibble is a half-byte, a group of 4 bits that corresponds to one character in a hexadecimal numeral system.
For convenience, binary numbers are often separated by spaces into nibbles. That is, instead of the entry 10011101110000101101111000101101, the entry 1001 1101 1100 0010 1101 1110 0010 1101 will be used.
Floating-point numbers
A floating-point number is an exponential form of representing real numbers where a number is stored as a mantissa and an exponent.
Below are some examples of such numbers:
125000 = 1.25 × 105 — here, the mantissa is 1.25 and the exponent is 5.
0.000000125 = 1.25 × 10−7 — here, the mantissa is 1.25 and the exponent is −7.
125000000000000 = 1.25 × 1014 — here, the mantissa is 1.25 and the exponent is 14.
The advantage of using such a notation is that it is possible to significantly expand the range of transmitted values while maintaining the number of bits involved.
The IEEE 754 standard is most commonly used to represent floating-point numbers in digital devices.
Practical application
In this section, different options for user parameters and formulas for their interpretation in Wialon will be considered.
A binary to an integer decimal number conversion
To understand the conversion formula, you should first look at decimal numbers from a slightly unusual perspective. We will consider the decimal number 125. It consists of one hundred, two tens, and five units: 125 = 1 × 100 + 2 × 10 + 5 × 1.
As we already know, the base of the decimal system is the number 10. We also note that hundreds are in the third position, tens are in the second position, and units are in the first position. With this in mind, the number can be represented as the sum of the values in each position multiplied by the base of the numeral system to a power equal to the base minus one:
125 = 1 × 103−1 + 2 × 102−1 + 5 × 101−1 = 1 × 102 + 2 × 101 + 5 × 100
To calculate a whole decimal number from binary, the same formula is used but the base will already be the number 2: the sum of the bits multiplied by the base of the number system to the power equal to the bit number minus one.
,
where d is a number in the decimal numeral system, i is the bit number of the binary number, N is the number of bits, and bi is the value of the i-th bit.
This formula can also be presented in the following way:
d = bN × 2N−1 + ... + bi × 2i−1 + ... + b2 × 22−1 + b1 × 21−1
Let’s consider an example with the same number:
(BIN) 0111 1101 = (DEC) 0 × 28−1 + 1 × 27−1 + 1 × 26−1 + 1 × 25−1 + 1 × 24−1 + 1 × 23−1 + 0 × 22−1 + 1 × 21−1 =
= (DEC) 0 × 27 + 1 × 26 + 1 × 25 + 1 × 24 + 1 × 23 + 1 × 22 + 0 × 21 + 1 × 20 = (DEC) 26 + 25 + 24 + 23 + 22 + 20 =
= (DEC) 64 + 32 + 16 + 8 + 4 + 1 = (DEC) 125.
If the value comes in a parameter named user_value, then, taking into account the Wialon syntax, the formula will take the following form:
user_value:8*const2^const7+user_value:7*const2^const6+user_value:6*const2^const5+user_value:5*const2^const4+user_value:4*const2^const3+user_value:3*const2^const2+user_value:2*const2^const1+user_value:1*const2^const0
This formula writing format seems longer, but it makes it easy to track the numbering of bits and powers, which makes it possible not to make mistakes when writing the formula. But if you know the powers of two well, then a simplified version of this formula may suit you:
user_value:8*const128+user_value:7*const64+user_value:6*const32+user_value:5*const16+user_value:4*const8+user_value:3*const4+user_value:2*const2+user_value:1*const1
The length of the conversion formula will depend on the number of bits taken into account, so copying it directly from the article will not work. If, according to the tracker protocol, 1 byte (8 bits) is allocated for the parameter value, then the formula will be similar to the one above (it will only be necessary to replace the parameter name in it). And if 3 bytes are allocated for the parameter, then the formula will be three times longer, and constants up to 223 = 8388608 will be used in it.
Extracting a part of a parameter
As mentioned earlier, sometimes a single parameter can contain several different values at once. In this case, you must use the formula given in the previous section but only consider some bits.
As an example, consider the user_value parameter with the value (DEC) 32200 = (BIN) 0111 1101 1100 1000. Its first byte describes the value of the first counter, and the second byte describes the value of another counter. It is necessary to create two separate sensors with formulas that will use only the required bytes.
Parameter | user_value | |||||||||||||||
Original value bit number | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
Bit value | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
Desired value bit number | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
Sensor | Counter #2 | Counter #1 |
The formula for the first sensor will be similar to the formula from the previous section since the bit numbers of the original and the desired values are the same:
user_value:8*const2^const7+user_value:7*const2^const6+user_value:6*const2^const5+user_value:5*const2^const4+user_value:4*const2^const3+user_value:3*const2^const2+user_value:2*const2^const1+user_value:1*const2^const0
The formula for the second sensor will be different since we will be accessing the bits 9-16 but treating them as the bits 1-8:
user_value:16*const2^const7+user_value:15*const2^const6+user_value:14*const2^const5+user_value:13*const2^const4+user_value:12*const2^const3+user_value:11*const2^const2+user_value:10*const2^const1+user_value:9*const2^const0
As a result, from one number 32200 we can get:
(BIN) 1100 1000 = (DEC) 200 — it is the value of the first counter.
(BIN) 0111 1101 = (DEC) 125 — it is the value of the second counter.
Considering the sign of a number
In some cases, the value of the high-order bit may not be significant, but signed, that is, it contains information not about the magnitude of the value, but about whether this number is positive or negative.
For example, if the tracker sends the value 13 or −5 in the user parameter, then Wialon does not know about it, and in both cases, we will see the same parameter user_value = 13, because:
(DEC) 13 = (BIN) 1101
(DEC) −5 = (BIN) 1101 — the high-order bit is responsible for the minus, and (BIN) 101 = (DEC) 5.
To interpret the sign bit correctly, you need to change the formula for converting a binary number to a decimal integer by adding to its beginning −1 to the power of the high-order bit:
,
where d is a number in the decimal numeral system, i is the bit number of the binary number, N is the number of bits, and bi is the value of the i-th bit.
This formula can also be presented in the following way:
d = (−1)bN × (bN-1 × 2(N−1)−1 + ... + bi × 2i−1 + ... + b2 × 22−1 + b1 × 21−1)
This formula works because (−1)0 = 1 and (−1)1 = −1 which allows you to display the sign of a number using one bit.
If we assume that the sign bit is a bit number 32, then to take it into account in Wialon, add the following formula to the beginning of the expression in the sensor:
(const-1)^user_value:32*...
A binary to a decimal floating-point number conversion
We are talking about converting a normalized binary number to a 32-bit format according to the IEEE 754 standard. This standard does not imply the transfer of the floating-point number itself, but the transfer of some values by which the desired number can be calculated using the following formula:
d = (−1)S × 2(E−127) × (1 + M/223),
where d is a number in the decimal numeral system, S is the sign of the number, E is the biased exponent, and M is the remainder of the normalized mantissa.
To apply this formula, its full understanding is not required. The standard describes which bits store S, E, and M so you just need to substitute them into the expression.
As an example, let’s consider the number −5.15811×10−21, which will be displayed in the parameter as user_value = 2646793773:
(DEC) 2646793773 = (BIN) 1001 1101 1100 0010 1101 1110 0010 1101
Sign bit (S) | Biased exponent (E) | Remainder of normalized mantissa (M) | |||||||||||||||||||||||||||||
32 | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
Using the formula for converting a binary number to a decimal integer, we obtain the values of M and E.
The remainder of the normalized mantissa M will be equal to:
user_value:23*const2^const22+user_value:22*const2^const21+user_value:21*const2^const20+user_value:20*const2^const19+user_value:19*const2^const18+user_value:18*const2^const17+user_value:17*const2^const16+user_value:16*const2^const15+user_value:15*const2^const14+user_value:14*const2^const13+user_value:13*const2^const12+user_value:12*const2^const11+user_value:11*const2^const10+user_value:10*const2^const9+user_value:9*const2^const8+user_value:8*const2^const7+user_value:7*const2^const6+user_value:6*const2^const5+user_value:5*const2^const4+user_value:4*const2^const3+user_value:3*const2^const2+user_value:2*const2^const1+user_value:1*const2^const0
The biased exponent E will be equal to:
user_value:31*const2^const7+user_value:30*const2^const6+user_value:29*const2^const5+user_value:28*const2^const4+user_value:27*const2^const3+user_value:26*const2^const2+user_value:25*const2^const1+user_value:24*const2^const0
Now let's write the final formula, taking into account the Wialon syntax:
(const-1^user_value:32)*const2^(user_value:31*const2^const7+user_value:30*const2^const6+
user_value:29*const2^const5+user_value:28*const2^const4+user_value:27*const2^const3+
user_value:26*const2^const2+user_value:25*const2^const1+user_value:24*const2^const0-const127)*(const1+
(user_value:23*const2^const22+user_value:22*const2^const21+user_value:21*const2^const20+
user_value:20*const2^const19+user_value:19*const2^const18+user_value:18*const2^const17+
user_value:17*const2^const16+user_value:16*const2^const15+user_value:15*const2^const14+
user_value:14*const2^const13+user_value:13*const2^const12+user_value:12*const2^const11+
user_value:11*const2^const10+user_value:10*const2^const9+user_value:9*const2^const8+
user_value:8*const2^const7+user_value:7*const2^const6+user_value:6*const2^const5+
user_value:5*const2^const4+user_value:4*const2^const3+user_value:3*const2^const2+
user_value:2*const2^const1+user_value:1*const2^const0)/const2^const23)
After a simplification, we get:
(const-1^user_value:32)*const2^(user_value:31*const128+user_value:30*const64+user_value:29*const32+
user_value:28*const16+user_value:27*const8+user_value:26*const4+user_value:25*const2+
user_value:24*const1-const127)*(const1+(user_value:23*const4194304+user_value:22*const2097152+
user_value:21*const1048576+user_value:20*const524288+user_value:19*const262144+
user_value:18*const131072+user_value:17*const65536+user_value:16*const32768+user_value:15*const16384+
user_value:14*const8192+user_value:13*const4096+user_value:12*const2048+user_value:11*const1024+
user_value:10*const512+user_value:9*const256+user_value:8*const128+user_value:7*const64+
user_value:6*const32+user_value:5*const16+user_value:4*const8+user_value:3*const4+user_value:2*const2+
user_value:1*const1)/const8388608)
When substituting the numbers, we get:
(−1)1 × 2(59−127) × (1 + 4382253/223) = −0.00000000000000000000515811 = −5.15811×10−21
As you can see, the result obtained differs significantly from the initial value of the parameter 2646793773.
From the following block, feel free to conveniently copy the formula for converting a binary number to a decimal floating-point number (IEEE 754 32-bit format):
(const-1^user_value:32)*const2^(user_value:31*const128+user_value:30*const64+user_value:29*const32+user_value:28*const16+user_value:27*const8+user_value:26*const4+user_value:25*const2+user_value:24*const1-const127)*(const1+(user_value:23*const4194304+user_value:22*const2097152+user_value:21*const1048576+user_value:20*const524288+user_value:19*const262144+user_value:18*const131072+user_value:17*const65536+user_value:16*const32768+user_value:15*const16384+user_value:14*const8192+user_value:13*const4096+user_value:12*const2048+user_value:11*const1024+user_value:10*const512+user_value:9*const256+user_value:8*const128+user_value:7*const64+user_value:6*const32+user_value:5*const16+user_value:4*const8+user_value:3*const4+user_value:2*const2+user_value:1*const1)/const8388608)